package com.xyb.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xyb.entity.Message;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 前端配套请求 url
 * ws://localhost:8080/websocket/12345
 */
@Component
@ServerEndpoint("/websocket/{courseId}/{userId}")
@Slf4j
public class WS_CourseChartRoomServer {

    /**
     * concurrent包线程安全 Set，用来存放每个客户端对应的 WebSocket 对象
     */
    private static ConcurrentHashMap<Long, ConcurrentHashMap<Long, CopyOnWriteArraySet<Session>>> map = new ConcurrentHashMap<>();

    private static ObjectMapper om = new ObjectMapper();

    //###########################  有新连接，处理数据	#########################
    @OnOpen
    public void open(Session session, @PathParam("courseId") Long courseId, @PathParam("userId") Long userId) {

        ConcurrentHashMap<Long, CopyOnWriteArraySet<Session>> userIdMap = map.get(courseId);     //是否存在该课程聊天室

        if (userIdMap == null) {    //说明该课程的聊天室还未创建
            ConcurrentHashMap<Long,CopyOnWriteArraySet<Session>> userIdMapTmp = new ConcurrentHashMap();    //创建用户id的 HashMap
            CopyOnWriteArraySet<Session> sessionSet = new CopyOnWriteArraySet<>();
            sessionSet.add(session);
            userIdMapTmp.put(userId, sessionSet);
            map.put(courseId, userIdMapTmp);
        } else {                    //说明该课程的聊天室已经创建
            CopyOnWriteArraySet<Session> sessionSet = userIdMap.get(userId);
            if(sessionSet==null||sessionSet.size()==0){
                sessionSet = new CopyOnWriteArraySet<>();
            }
            sessionSet.add(session);
            userIdMap.put(userId, sessionSet);
        }

        showOnLineView(); //展示
        sendOnLineNum(courseId); // 推送在线人数
    }

    //########################################################################


    //**************************** 有连接断开时处理数据  ************************
    @OnClose
    public void close(Session session, @PathParam("courseId") Long courseId, @PathParam("userId") Long userId) {
        //从 set 集合里移除当前对象
        ConcurrentHashMap<Long, CopyOnWriteArraySet<Session>> userIdMap = WS_CourseChartRoomServer.map.get(courseId);

        CopyOnWriteArraySet<Session> sessionSet = userIdMap.get(userId);
        sessionSet.remove(session);
        if(sessionSet.size()==0){
            userIdMap.remove(userId);
        }
        if(userIdMap == null||userIdMap.size() == 0){
            map.remove(courseId);
        }else{
            sendOnLineNum(courseId);// 推送在线人数
        }
        showOnLineView(); //展示
    }

    //**********************************************************************

    //当前所有连接数
    private static synchronized int getOnlineCount(Long courseId) {
        return map.get(courseId).size();
    }


    //############## 给所有人推送 ##############
    public void sendMessage2CourseById(Message msg) {
        ConcurrentHashMap<Long, CopyOnWriteArraySet<Session>> userIdMap = WS_CourseChartRoomServer.map.get(msg.getCourseId());
        msg.setOnLineNum(getOnlineCount(msg.getCourseId()));

        userIdMap.forEach((userId,sessionSet)->{

            try {
                String text = om.writeValueAsString(msg);
                sessionSet.forEach(session->{
                    try {
                        session.getBasicRemote().sendText(text);
                    } catch (IOException e) {
                        log.error("WebSocket 推送异常");
                    }
                });
            } catch (JsonProcessingException e) {
                log.error("对象转换异常");
            }

        });
    }

    public void sendOnLineNum(Long courseId){
        map.forEach((k,v)->{

        });
        ConcurrentHashMap<Long, CopyOnWriteArraySet<Session>> userIdMap = WS_CourseChartRoomServer.map.get(courseId);

        Message msg = new Message();
        msg.setCourseId(-1L);
        msg.setOnLineNum(getOnlineCount(courseId));

        userIdMap.forEach((userId,sessionSet)->{
            try {
                String text = om.writeValueAsString(msg);
                sessionSet.forEach(session->{
                    try {
                        session.getBasicRemote().sendText(text);
                    } catch (IOException e) {
                        log.error("WebSocket 推送异常");
                    }
                });
            } catch (JsonProcessingException e) {
                log.error("对象转换异常");
            }

        });
    }
    //#########################################################################


    private static void showOnLineView(){
        log.info("======================================================================================================");
        map.forEach((courseId,userIdMap)->{
            log.info("课程编号: " + courseId + " 当前在线人数: " + userIdMap.size());
            userIdMap.forEach((userId,sessionSet)->{
                log.info("\t用户id: " + userId);
                sessionSet.forEach(session->{
                   log.info("\t\tSession 编号: " + session);
                });
            });
        });
    }
}
